home *** CD-ROM | disk | FTP | other *** search
/ PsL Monthly 1993 December / PSL Monthly Shareware CD-ROM (December 1993).iso / prgmming / win / pascal / ddeconv.exe / DDECONV.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1992-11-26  |  13.7 KB  |  486 lines

  1. {************************************************}
  2. {                                                }
  3. {   ddeconv.pas                                  }
  4. {   Turbo Pascal for Windows demo program        }
  5. {   by Klemens Schmid, 100114, 1475              }
  6. {                                                }
  7. {   This program implements a simple DDE         }
  8. {   conversion with any DDE client (Excel,       }
  9. {   WinWord, ProgMan etc.                        }
  10. {                                                }
  11. {************************************************}
  12.  
  13. program DDEconveration;
  14.  
  15. uses WinTypes, WinProcs, WObjects, Strings, ShellApi;
  16.  
  17. {$R DDECONV}
  18.  
  19. const
  20.  
  21. { Resource IDs }
  22.  
  23.   id_DDEDialog    = 100;
  24.  
  25. { DDE dialog item IDs }
  26.  
  27.   id_Applic      = 100;
  28.   id_Topic       = 101;
  29.   id_Data        = 102;
  30.   id_Result      = 103;
  31.   id_initiate    = 104;
  32.   id_Terminate   = 105;
  33.   id_Request     = 106;
  34.   id_Poke        = 107;
  35.   id_Advise      = 108;
  36.   id_Execute     = 109;
  37.   id_Item        = 110;
  38.  
  39. {bits in TDDEdata.Flags}
  40.   DDE_fAckReq    = $8000;
  41.   DDE_fDeferUpd = $4000;
  42.   DDE_fRelease   = $2000;
  43.   DDE_fRequested = $1000;
  44.   DDE_fAck       = $0001;
  45.  
  46. type
  47.  
  48.   DlgDataDescr= record
  49.      StrApplic,StrTopic,StrItem,StrData,StrResult : array[0..79] of char;
  50.   end;
  51.  
  52.   PDDEWindow = ^TDDEWindow;
  53.   TDDEWindow = object(TDlgWindow)
  54.     DlgData : DlgDataDescr;
  55.     EditApplic,EditTopic,EditItem,EditData,EditResult : PEdit;
  56.     ServerWindow: HWnd;
  57.     PendingMessage: Word;
  58.     HData : THandle;
  59.     constructor Init;
  60.     procedure SetupWindow; virtual;
  61.     function GetClassName: PChar; virtual;
  62.     procedure cmInitiate(var Msg: TMessage);
  63.       virtual id_First + id_Initiate;
  64.     procedure cmTerminate(var Msg: TMessage);
  65.       virtual id_First + id_Terminate;
  66.     procedure cmRequest(var Msg: TMessage);
  67.       virtual id_First + id_Request;
  68.     procedure cmPoke(var Msg: TMessage);
  69.       virtual id_First + id_Poke;
  70.     procedure cmAdvise(var Msg: TMessage);
  71.       virtual id_First + id_Advise;
  72.     procedure cmExecute(var Msg: TMessage);
  73.       virtual id_First + id_Execute;
  74.  
  75.     {DDE messages}
  76.     procedure InitiateDDE;
  77.     procedure TerminateDDE;
  78.     procedure PokeDDE(Item:PChar; DataFormat:Word; Data:Pointer; DataSize:Word);
  79.     procedure AdviseDDE(DataFormat:Word; Item:PChar);
  80.     procedure RequestDDE(DataFormat:Word; Item:PChar);
  81.     procedure WMDDEAck(var Msg: TMessage);
  82.       virtual wm_First + wm_DDE_Ack;
  83.     procedure WMDDETerminate(var Msg: TMessage);
  84.       virtual wm_First + wm_DDE_Terminate;
  85.     procedure WMDDEData(var Msg: TMessage);
  86.       virtual wm_First + wm_DDE_Data;
  87.     procedure WMDestroy(var Msg: TMessage);
  88.       virtual wm_First + wm_Destroy;
  89.   end;
  90.  
  91. { TDDEApp is the application object. It creates a main window of type
  92.   TDDEWindow. }
  93.  
  94.   TDDEApp = object(TApplication)
  95.     procedure InitMainWindow; virtual;
  96.   end;
  97.  
  98. { TDDEWindow }
  99.  
  100. { DDE window constructor. Create all edit x object to represent the
  101.   dialog's list box. Clear the DDE server window handle and the
  102.   pending DDE message ID. }
  103.  
  104. constructor TDDEWindow.Init;
  105. begin
  106.   TDlgWindow.Init(nil, 'DDE');
  107.   EditApplic:= New(PEdit, InitResource(@Self, id_Applic,80));
  108.   EditTopic := New(PEdit, InitResource(@Self, id_Topic, 80));
  109.   EditItem  := New(PEdit, InitResource(@Self, id_Item, 80));
  110.   EditData  := New(PEdit, InitResource(@Self, id_Data, 80));
  111.   EditResult:= New(PEdit, InitResource(@Self, id_Result, 80));
  112.   ServerWindow := 0;
  113.   PendingMessage := 0;
  114. end;
  115.  
  116. { SetupWindow is called right after the DDE window is created.}
  117.  
  118. procedure TDDEWindow.SetupWindow;
  119. begin
  120.   TDlgWindow.SetupWindow;
  121.   Transferbuffer:=@DlgData;
  122.   EnableTransfer;
  123. end;
  124.  
  125. { Return window class name. This name corresponds to the class name
  126.   specified for the DDE dialog in the resource file. }
  127.  
  128. function TDDEWindow.GetClassName: PChar;
  129. begin
  130.   GetClassName := 'DDEWindow';
  131. end;
  132.  
  133. { Is called when the "Initiate" button is pressed}
  134.  
  135. procedure TDDEWindow.cmInitiate;
  136. begin
  137.   InitiateDDE; { start
  138. end;
  139.  
  140. { Is called when the "Terminate" button is pressed}
  141.  
  142. procedure TDDEWindow.cmTerminate;
  143. begin
  144.   TerminateDDE;
  145. end;
  146.  
  147. { Is called when the "Request" button is pressed. Fetch the value
  148.   of the server field denoted by "Item" and display it in field "Data" }
  149.  
  150. procedure TDDEWindow.cmRequest;
  151. begin
  152.   TransferData(tf_GetData);
  153.   RequestDDE(cf_Text,DlgData.StrItem);
  154. end;
  155.  
  156. { Is called when the "Poke" button is pressed. Enter the value
  157.   given in "Data" in the server field denoted by "Item" }
  158.  
  159. procedure TDDEWindow.cmPoke;
  160. var
  161.    p : integer;
  162. begin
  163.   TransferData(tf_GetData);
  164.   with DlgData do begin
  165.     p:=StrLen(StrData);
  166.     StrData[p]:=#13;
  167.     StrData[p+1]:=#10;
  168.     StrData[p+2]:=#0;
  169.     PokeDDE(StrItem,cf_Text,@StrData,StrLen(StrData)+1);
  170.   end;
  171. end;
  172.  
  173. { Is called when the "Advise" button is pressed. Establishes a hot
  174.   link for the field denoted in "Item" }
  175.  
  176. procedure TDDEWindow.cmAdvise;
  177. begin
  178.   TransferData(tf_GetData);
  179.   AdviseDDE(cf_Text,DlgData.StrItem);
  180. end;
  181.  
  182. {
  183. procedure TDDEWindow.PokeDDE;
  184. var
  185.    DataRecord:TDDEData;
  186.    lParam:LongInt;
  187.    ItemGlobalAtom : Word;
  188.    PCommands:Pointer;
  189.    Executed : boolean;
  190.  
  191. begin
  192.    HData :=GlobalAlloc(gmem_Moveable or gmem_DDEshare,
  193.                           SizeOf(TDDEdata) + DataSize);
  194.    Executed := false;
  195.    if (HData <> 0 ) then begin
  196.       PCommands := GlobalLock(HData);
  197.       if PCommands = nil then
  198.          GlobalFree(HData)
  199.       else begin
  200.          DataRecord.cfFormat := DataFormat;
  201.          Move(DataRecord,PCommands^,SizeOf(DataRecord));
  202.          Move(Data^,PDDEdata(PCommands)^.Value,DataSize);
  203.          GlobalUnLock(HData);
  204.          ItemGlobalAtom := GlobalAddAtom(Item);
  205.          lParam := ItemGlobalAtom;
  206.          lParam := (lParam shl 16) or HData;
  207.          if PostMessage(ServerWindow, wm_DDE_Poke, HWIndow,lParam) then begin
  208.             PendingMessage := wm_DDE_Poke;
  209.             Executed := True;
  210.             end
  211.          else begin
  212.             GlobalFree(HData);
  213.             GlobalDeleteAtom(ItemGlobalAtom);
  214.          end;
  215.       end
  216.    end;
  217.    if not Executed then
  218.      MessageBox(HWindow, 'DDE execute failed.',
  219.        'Error', mb_IconExclamation or mb_Ok);
  220. end;
  221.  
  222.  
  223. procedure TDDEWindow.RequestDDE;
  224. var
  225.    lParam:LongInt;
  226.    ItemGlobalAtom : Word;
  227.    Executed : boolean;
  228.  
  229. begin
  230.    Executed := false;
  231.    ItemGlobalAtom := GlobalAddAtom(Item);
  232.    lParam := ItemGlobalAtom;
  233.    lParam := (lParam shl 16) or DataFormat;
  234.    if PostMessage(ServerWindow, wm_DDE_Request, HWIndow,lParam) then begin
  235.       PendingMessage := wm_DDE_Request;
  236.       Executed := True;
  237.       end
  238.    else begin
  239.       GlobalDeleteAtom(ItemGlobalAtom);
  240.    end;
  241.    if not Executed then
  242.      MessageBox(HWindow, 'DDE request failed.',
  243.        'Error', mb_IconExclamation or mb_Ok);
  244. end;
  245.  
  246.  
  247. procedure TDDEWindow.AdviseDDE;
  248. var
  249.    lParam:LongInt;
  250.    ItemGlobalAtom : Word;
  251.    Executed  : boolean;
  252.    PCommands : PDDEdata;
  253.  
  254. begin
  255.    Executed := false;
  256.    ItemGlobalAtom := GlobalAddAtom(Item);
  257.    HData := GlobalAlloc(gmem_Moveable or gmem_DDEshare,sizeof(TDDEdata));
  258.    if HData <> 0 then begin
  259.      PCommands := GlobalLock(HData);
  260.      if PCommands = nil then
  261.         GlobalFree(HData)
  262.      else begin
  263.         PCommands^.cfFormat := DataFormat;
  264.         PCommands^.Flags := 0; {DDE_FAckReq or DDE_FDeferUpd;}
  265.         GlobalUnLock(HData);
  266.         lParam := ItemGlobalAtom;
  267.         lParam := (lParam shl 16) or HData;
  268.         if PostMessage(ServerWindow, wm_DDE_Advise, HWIndow,lParam) then begin
  269.            PendingMessage := wm_DDE_Advise;
  270.            Executed := True;
  271.            end
  272.         else begin
  273.            GlobalDeleteAtom(ItemGlobalAtom);
  274.            GlobalFree(HData);
  275.         end;
  276.      end;
  277.    end; {if HData}
  278.    if not Executed then
  279.      MessageBox(HWindow, 'DDE advise failed (1)',
  280.        'Error', mb_IconExclamation or mb_Ok);
  281. end;
  282.  
  283.  
  284. { Initiate a DDE conversation with a server application. Application
  285.   name and topic name is taken from corresponding Edit fields. Note
  286.   than SendMessage is used here in contradiction to other cases.
  287.   If server application isn't up it is started via ShellExecute. }
  288.  
  289. procedure TDDEWindow.InitiateDDE;
  290. var
  291.   AppAtom, TopicAtom: TAtom;
  292. begin
  293.   TransferData(tf_GetData);
  294.   PendingMessage := wm_DDE_Initiate;
  295.   AppAtom := GlobalAddAtom(DlgData.StrApplic);
  296.   TopicAtom := GlobalAddAtom(DlgData.StrTopic);
  297.   if GetModuleHandle(DlgData.StrApplic) = 0 then  {application no active}
  298.      ShellExecute(HWindow,nil,DlgData.StrApplic,DlgData.StrTopic,nil,sw_Show);
  299.   SendMessage(HWnd(-1), wm_DDE_Initiate, HWindow,
  300.     MakeLong(AppAtom, TopicAtom));
  301.   GlobalDeleteAtom(AppAtom);
  302.   GlobalDeleteAtom(TopicAtom);
  303.   PendingMessage := 0;
  304.   if ServerWindow = 0 then
  305.     MessageBox(HWindow, 'Cannot establish DDE link',
  306.       'Error', mb_IconExclamation or mb_Ok);
  307. end;
  308.  
  309. { Terminate the DDE conversation. Send the wm_DDE_Terminate message
  310.   only if the server window still exists. }
  311.  
  312. procedure TDDEWindow.TerminateDDE;
  313. var
  314.   W: HWnd;
  315. begin
  316.   W := ServerWindow;
  317.   ServerWindow := 0;
  318.   if IsWindow(W) then PostMessage(W, wm_DDE_Terminate, HWindow, 0);
  319. end;
  320.  
  321. { trigger DDE server application to execute the command provided
  322.   in the Edit field "Data". Only makes sense for commands under-
  323.   standable by the server. }
  324.  
  325. procedure TDDEWindow.cmExecute(var Msg: TMessage);
  326. var
  327.   Executed: Boolean;
  328.   I, L: Integer;
  329.   PName, PCommands: PChar;
  330.   Name: array[0..63] of Char;
  331. begin
  332.   TransferData(tf_GetData);
  333.   Executed := False;
  334.   if (ServerWindow <> 0) and (PendingMessage = 0) then
  335.   begin
  336.     L := StrLen(DlgData.StrData) +1;
  337.     HData := GlobalAlloc(gmem_Moveable or gmem_DDEShare, L);
  338.     if HData <> 0 then
  339.     begin
  340.       PCommands := GlobalLock(HData);
  341.       StrCopy(PCommands,DlgData.StrData);
  342.       GlobalUnlock(HData);
  343.       if PostMessage(ServerWindow, wm_DDE_Execute, HWindow,
  344.         MakeLong(0, HData)) then
  345.       begin
  346.         PendingMessage := wm_DDE_Execute;
  347.         Executed := True;
  348.       end else GlobalFree(HData);
  349.     end;
  350.   end;
  351.   if not Executed then
  352.     MessageBox(HWindow, 'DDE execute failed.',
  353.       'Error', mb_IconExclamation or mb_Ok);
  354. end;
  355.  
  356. { wm_DDE_Ack message response method is called of the server answers
  357.   to one of our messages Initiate, Terminate, Request, Advise,
  358.   Execute or Poke. Aside from other things it frees the handles
  359.   sent by the server. }
  360.  
  361. procedure TDDEWindow.WMDDEAck(var Msg: TMessage);
  362. begin
  363.   case PendingMessage of
  364.     wm_DDE_Initiate:
  365.       begin
  366.         if ServerWindow = 0 then begin
  367.           ServerWindow := Msg.WParam;
  368.           GlobalGetAtomName(Msg.lParamLo,DlgData.StrResult,79);
  369.           TransferData(tf_SetData);
  370.           Show(sw_Show);
  371.           end
  372.         else
  373.           PostMessage(Msg.WParam, wm_DDE_Terminate, HWindow, 0);
  374.         GlobalDeleteAtom(Msg.LParamLo);
  375.         GlobalDeleteAtom(Msg.LParamHi);
  376.       end;
  377.     wm_DDE_Execute:
  378.       begin
  379.         GlobalFree(Msg.LParamHi);
  380.       if Msg.lParamLo = 0 then {negative ackn}
  381.          GlobalFree(HData)
  382.       else
  383.          GlobalFree(Msg.LParamHi);
  384.         PendingMessage := 0;
  385.         SetFocus(HWindow);
  386.       end;
  387.     wm_DDE_Poke:
  388.       begin
  389.         GlobalFree(Msg.LParamHi);
  390.       if Msg.lParamLo = 0 then {negative ackn}
  391.          GlobalFree(HData)
  392.       else
  393.          GlobalFree(Msg.LParamHi);
  394.         PendingMessage := 0;
  395.         SetFocus(HWindow);
  396.       end;
  397.     wm_DDE_Request:
  398.       begin
  399.       GlobalDeleteAtom(Msg.LParamHi);
  400.       MessageBox(HWindow, 'DDE data not received',
  401.         'Error', mb_IconExclamation or mb_Ok);
  402.       end;
  403.     wm_DDE_Advise:
  404.       begin
  405.       GlobalDeleteAtom(Msg.LParamHi);
  406.       if Msg.lParamLo = 0 then begin {negative ackn}
  407.          GlobalFree(HData);
  408.          MessageBox(HWindow, 'DDE advise failed (2)',
  409.            'Error', mb_IconExclamation or mb_Ok);
  410.          end
  411.       else
  412.          GlobalFree(Msg.LParamLo);
  413.       end;
  414.   end;
  415. end;
  416.  
  417. { This procedure is triggered if the server send a data value either
  418.   in response to a DDE "Request" or "Advise" if the value of the
  419.   hot linked data item has changed }
  420.  
  421. procedure TDDEWindow.WMDDEData(var Msg: TMessage);
  422. var
  423.    p:PDDEData;
  424.    lParam : longint;
  425.    DataRecord : TDDEdata;
  426. begin
  427.    GlobalGetAtomName(Msg.lParamHi,DlgData.StrItem,79);
  428.    p:=GlobalLock(Msg.lParamLo);  {ptr to DDEdata}
  429.    if p = nil then begin {we have to request}
  430.       GlobalFree(Msg.lParamLo);
  431.       GLobalDeleteAtom(Msg.lParamHi);
  432.       RequestDDE(cf_Text,DlgData.StrItem);
  433.       exit;
  434.    end;
  435.    Move(P^,DataRecord,Sizeof(DataRecord));
  436.    StrCopy(@DlgData.StrResult,@P^.Value);
  437.    GlobalUnlock(Msg.lParamLo);
  438.    if (DataRecord.Flags or DDE_fRelease) <> 0 then
  439.       GlobalFree(Msg.lParamLo);
  440.    if (DataRecord.Flags or DDE_fAckReq) <> 0 then begin
  441.       lParam:=DDE_FAckReq or (Msg.lParamHi shl 16);
  442.       if not PostMessage(ServerWindow,wm_DDE_Ack,HWindow,lParam)  then
  443.          GLobalDeleteAtom(Msg.lParamHi); {use the old atom}
  444.    end;
  445.    TransferData(tf_SetData);
  446.    Show(sw_Show);
  447. end;
  448.  
  449. { wm_DDE_Terminate message response method. If the window signaling
  450.   termination is our server window, terminate
  451.   the DDE conversation. Otherwise ignore the wm_DDE_Terminate. }
  452.  
  453. procedure TDDEWindow.WMDDETerminate(var Msg: TMessage);
  454. begin
  455.   if Msg.WParam = ServerWindow then TerminateDDE;
  456. end;
  457.  
  458.  
  459. { wm_Destroy message response method. Terminate the DDE link and
  460.   call the inherited WMDestroy. }
  461.  
  462. procedure TDDEWindow.WMDestroy(var Msg: TMessage);
  463. begin
  464.   TerminateDDE;
  465.   TDlgWindow.WMDestroy(Msg);
  466. end;
  467.  
  468.  
  469. { TDDEApp }
  470.  
  471. { Create a DDE window as the application's main window. }
  472.  
  473. procedure TDDEApp.InitMainWindow;
  474. begin
  475.   MainWindow := New(PDDEWindow, Init);
  476. end;
  477.  
  478. var
  479.   DDEApp: TDDEApp;
  480.  
  481. begin
  482.   DDEApp.Init('DDEconv');
  483.   DDEApp.Run;
  484.   DDEApp.Done;
  485. end.
  486.